//////////////////////////////////////////////////////////////////////////
//
// This file is a part of XORT project.
//
// PROJECT:         Xort compiler execution subsystem
// FILE:            xruntime.cpp
// AUTHOR:          Vladimir Gumenuk
// DATE:            7-Dec-2012
// MODIFICATIONS:
//
//
//     Copyright(c) 2014, Vladimir Gumenuk
//     All rights reserved.
//
//     Redistribution and use in source and binary forms, with or without modification, 
//     are permitted provided that the following conditions are met :
//
//     1. Redistributions of source code must retain the above copyright notice, 
//        this list of conditions and the following disclaimer.
//     2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and 
//        the following disclaimer in the documentation and / or other materials provided with the distribution.
//     3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse 
//        or promote products derived from this software without specific prior written permission.
//
//     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
//     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
//     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
//     THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
//     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
//     OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
//     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 
//     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 
//     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "xort.h"
#include "xruntime.h"
#include "xobject.h"
#include "xniobject.h"
#include "xbuildin.h"
#include "xprimimpl.h"
#include "xcode.h"
#include "BuildinObjectInfo.h"
#include "listImpl.h"
#include "XortStringImpl.h"
#include "XortElementImpl.h"

#ifdef BUILD_FOR_PC
    #include <windows.h>
    #include "listImpl.cpp"
#elif defined( BUILD_FOR_MAC )
    #include <dlfcn.h>
#endif

// initialize runtime subsystem: creates Memory DATA block, function block, prepares stack 
XRuntime::XRuntime()
{
    m_dwIP                  = 0;
    m_dwExecutedPrimsCount  = 0;
    m_dwCallsRecursionDepth = 0;
    m_dwMaxRecursionDepth   = 0;
    m_pDbgEvents            = NULL;
    m_pSymList              = NULL;
    m_pLitPool              = NULL;
    m_pCurrentProc          = NULL;
    m_pcsRuntimeName        = NULL;
    memset( &m_dwExecPrimsCounter[ 0 ], 0, PRIMS_COUNTER_SIZE * sizeof( dword ) );
}

int XRuntime::Initialize( SYMBOLLIST symList, STRINGARRAY litPool, XRuntimeDebugEvents *pEventsSink )
{
    m_pSymList = &symList;
    m_pLitPool = &litPool;
    m_pDbgEvents = pEventsSink;
    
    SymbolRef symStr = FindType( *m_pSymList, t_string );
    int iRet = createXObject( symStr, NULL, (xobject**)&m_pcsRuntimeName );
    if( iRet != XORT_OK )
        return iRet;
    
    return InitInternal();
}

int XRuntime::InitInternal()
{
    int iRet = XORT_OK;
    XortElement xFrame;
    xFrame._u8 = 0;
    xFrame.bType = 0;
    xFrame.bAccess = sys_Frame;
    m_dwStackBase = m_Stack.push( xFrame ); // create system frame on arith stack
    xFrame.bType = t_u4;
    m_RetStack.push( xFrame );              // create system frame on return stack

    SymbolListInfo symListInfo;
    GetSymbolListInfo( *m_pSymList, symListInfo );

    m_Data.reserve( symListInfo.dwVariblesCount+1 );
    m_Functions.reserve( symListInfo.dwFunctionsCount+1 );

    dword dwVarsCount = 0;
    dword dwProcsCount = 0;

    // init data block
    SYMBOL_LIST::iterator theIter = m_pSymList->begin();
    symbolref pSym = (Symbol*)theIter;
    while( pSym )
    {
        if( pSym->m_SymKind == sk_var ) // global variable
        {
            if( pSym->m_dwStorage == cSTORAGE_STACK || pSym->m_dwStorage == cSTORAGE_MEMBER )
                return ERR_INVALID_STORAGE; // global variables can persist only in memory!

            if( pSym->m_dwType == t_p )
                return ERR_RAWPTR_TYPE_FOUND;

            XortElement x;
            if( pSym->m_dwType > t_p )
            {
                SymbolRef varType = FindType( *m_pSymList, pSym->m_dwType );
                if( varType.isNULL() )
                    return ERR_TYPE_NOT_FOUND;

                if( varType.m_dwType == t_string )
                {
                    if( pSym->m_dwLiteralIdx ) {
                        x._p = m_pLitPool->get( pSym->m_dwLiteralIdx );
                        x._p->AddRef();
                    } else {
                        if( pSym->m_Value.bType != t_v ) { // handle case if user initialize object like "string s = NULL;"
                            if( pSym->m_Value.bType != t_p || pSym->m_Value._p != NULL )
                                return ERR_INVALID_TYPE;
                            x._p = NULL;
                        } else { // create empty string object
                            iRet = createXObject( varType, NULL, &x._p );
                            if( iRet != XORT_OK )
                                return iRet;
                        }
                    }
                } else { // build user complex type - object
                    if( pSym->m_Value.bType != t_v ) { // handle initialization with NULL
                        if( pSym->m_Value.bType != t_p || pSym->m_Value._p != NULL )
                            return ERR_INVALID_TYPE;
                        x._p = NULL;
                    } else {
                        iRet = createXObject( varType, NULL, &x._p );
                        if( iRet != XORT_OK )
                            return iRet;
                    }
                }

            } else {
                x = pSym->m_Value;
            }

            x.bType   = ( pSym->m_dwType > t_p ) ? t_p : pSym->m_dwType;
            x.bAccess = ( pSym->m_dwFlags & f_const ) ? usr_VarR : usr_VarRW; // setup constant flag

            m_Data.put( pSym->m_iIndex, x );
            dwVarsCount++;
        }
        else
        if( pSym->m_SymKind == sk_proc ) // global function
        {
            if( pSym->m_dwStorage == cSTORAGE_STACK || pSym->m_dwStorage == cSTORAGE_MEMBER )
                return ERR_INVALID_STORAGE; 

            if( pSym->m_dwFlags & f_import_proc ) { // here is procedure that is imported from some native dll
                
                dword dwAttrCount = pSym->m_arAttributes.count();
                int bProc = FALSE;
                string csName, csModule, csPlatform;
                
                for( dword i = 0; i < dwAttrCount; i++ ) {
                    AttributesRef pAttr = pSym->m_arAttributes.get( i );

                    switch( pAttr->dwAttrCode )
                    {
                    case attr_import:
                        if( pAttr->csAttrValue.Compare( "proc" ) != 0 ) return ERR_UNKNOWN_ATTRIBUTE;
                        bProc = TRUE; 
                        break;
                    case attr_name:   csName   = pAttr->csAttrValue; break;
                    case attr_module: csModule = pAttr->csAttrValue; break;
                    case attr_callconv: 
                        if( pAttr->csAttrValue.Compare( "pascal" ) == 0 ) {
                            pSym->m_CC = cc_pascal;
                        } else if( pAttr->csAttrValue.Compare( "cdecl" ) == 0 ) {
                            pSym->m_CC = cc_cdecl;
                        } else if( pAttr->csAttrValue.Compare( "stdcall" ) == 0 ) {
                            pSym->m_CC = cc_stdcall;
                        } else 
                            return ERR_UNKNOWN_ATTRIBUTE;
                        break;
                    case attr_platform: csPlatform = pAttr->csAttrValue; break;
                    default:return ERR_UNKNOWN_ATTRIBUTE;
                    }
                }

                if( !bProc || csName.IsEmpty() || csModule.IsEmpty() || pSym->m_CC == cc_unknown )
                    return ERR_UNKNOWN_ATTRIBUTE;
#ifdef BUILD_FOR_PC
                if( csPlatform.Compare( "windows" ) != 0 ) return ERR_INVALID_PLATFORM;
                HINSTANCE hDLL = ::LoadLibraryA( CONST_CHAR_PTR csModule );
                if( !hDLL ) return ERR_LOAD_LIBRARY_FAIL;
                pSym->m_pfnNative = (void *) ::GetProcAddress( hDLL, CONST_CHAR_PTR csName );
#elif defined( BUILD_FOR_MAC )
                if( csPlatform.Compare( "osx" ) != 0 ) return ERR_INVALID_PLATFORM;
                void *hDLL = dlopen( CONST_CHAR_PTR csModule, RTLD_LAZY );
                if( !hDLL ) return ERR_LOAD_LIBRARY_FAIL;
                pSym->m_pfnNative = (void *) dlsym( hDLL, CONST_CHAR_PTR csName );
#endif
                if( pSym->m_pfnNative == NULL )
                    return ERR_GET_PROC_ADDR_FAIL;

            } else { // xort proc, test code
                //if( pSym->m_Code.count() == 0 ) {
                //    return ERR_PROC_NOT_IMPLEMENTED;
                //}
            }

            iRet = xc_removeLabels( *pSym ); // remove all labels and optimize goto
            if( iRet != XORT_OK )
                return iRet;

            pSym->GenerateIPLineMap();
            m_Functions.put( pSym->m_iIndex, pSym );
            dwProcsCount++;
        } // else we skip all other type names

        theIter++;
        pSym = theIter == NULL ? NULL : (Symbol*)theIter;
    }

    m_Data.set_itemsCount( dwVarsCount + 1 );
    m_Functions.set_itemsCount( dwProcsCount + 1 );
    return XORT_OK;
}

XRuntime::~XRuntime()
{
    m_pDbgEvents = NULL;

    if( m_pcsRuntimeName ) 
        m_pcsRuntimeName->Release();

    dword dwCount = m_Data.count();
    for( dword i = 0; i < dwCount; i++ ) {
        m_Data[ i ].Clear();
    }
    m_Functions.clear();
    m_Stack.clear();
}

 // resets XVM to initial state after internal error. After this method Run or Exec can be called again
void XRuntime::Reset()
{
    m_dwIP                  = 0;
    m_dwExecutedPrimsCount  = 0;
    m_dwCallsRecursionDepth = 0;
    m_dwMaxRecursionDepth   = 0;
    m_pCurrentProc          = NULL;

    // zero counter for primitives
    memset( &m_dwExecPrimsCounter[ 0 ], 0, PRIMS_COUNTER_SIZE * sizeof( dword ) );

    dword dwCount = m_Data.count();
    for( dword i = 0; i < dwCount; i++ ) {
        m_Data[ i ].Clear();
    }
    m_Functions.clear();
    m_Stack.clear();

    InitInternal(); // reinit
}

int XRuntime::Run( SymbolRef entryPoint, int argc, char *argv[] )
{
    // create stack frame for main function: main( STRINGARRAY args );
    SymbolRef strArSymbol = FindTemplateType( *m_pSymList, t_array, t_string );

    if( !strArSymbol.isNULL() ) // user declared string array, so create frame with arguments to main function
    {
        xobjectref pArgs = NULL;
        int iRet = createXObject( strArSymbol, NULL, &pArgs );
        if( iRet != XORT_OK )
            return iRet;

        xarray_xo *pArgsArray = (xarray_xo *)pArgs;

        XortElement arg;
        arg.SetValue( pArgs ); 
        arg.bAccess = usr_VarR; // make arguments array read-only
        arg.bType = t_p;
        m_Stack.push( arg ); // set the array of arguments
        pArgsArray->Release(); // -ref, forgot it first :)

        XortElement xFrame; 
        xFrame._u8 = 0;
        xFrame.bType = 1;    // arg count
        xFrame.bAccess = sys_Frame;
        m_dwStackBase = m_Stack.push( xFrame );
        xFrame.bType = t_u4;
        m_RetStack.push( xFrame );              // create system frame on return stack

        if( argc > 2 ) // 1 arg - path to XVM, 2 arg - path to target executable
        {
            SymbolRef symStr = FindType( *m_pSymList, t_string );
        
            for( int i = 0; i < argc; i++ )
            {
                char *lpszStr = argv[i];
            
                xstring *pStr = NULL;
                iRet = createXObject( symStr, NULL, (xobject**)&pStr );
                if( iRet != XORT_OK )
                    return iRet;

                pStr->Assign( lpszStr );
                pArgsArray->add( pStr );
                pStr->Release();            
            }
        }
    } // seems, that function declared like xxx main()...

    return Exec( entryPoint );
}

// Historically - this is debug version of the main exec routine.
// Release version needs to be implemented.
int XRuntime::Exec( SymbolRef entryPoint )
{
    int iRet = XORT_OK;

    if( entryPoint.m_SymKind != sk_proc ) {
        if( m_pDbgEvents ) m_pDbgEvents->internalXVMError( this, ERR_SYMBOL_NOT_PROC );
        return ERR_SYMBOL_NOT_PROC;
    }
    
    m_dwCallsRecursionDepth++;
    if( m_dwCallsRecursionDepth > m_dwMaxRecursionDepth )
        m_dwMaxRecursionDepth = m_dwCallsRecursionDepth;
    
    //DebugMessage( "---> Entering function: '%s'", CONST_CHAR_PTR entryPoint.m_csName );
    if( m_pDbgEvents ) m_pDbgEvents->onEnterSystemFrame( this, entryPoint );

    if( entryPoint.m_dwFlags & f_buildinfunc ) // call build in function
    {
        if( m_pDbgEvents ) m_pDbgEvents->beforeExecBuildinProc( this );

        iRet = exec_buildin_proc( entryPoint, this );

        if( m_pDbgEvents ) m_pDbgEvents->afterExecBuildinProc( this, iRet );
    }
    else if( entryPoint.m_dwFlags & f_import_proc )
    {
        if( m_pDbgEvents ) m_pDbgEvents->beforeExecNativeProc( this );

        iRet = exec_native_proc( entryPoint, this );

        if( m_pDbgEvents ) m_pDbgEvents->afterExecNativeProc( this, iRet );

    } else { // XVM regular proc...

        m_pCurrentProc = &entryPoint; // store current proc

        m_dwFLAGS = 0;
        m_dwIP    = 0;

        dword dwNumInstructions = entryPoint.m_Code.count();

        while( m_dwIP < dwNumInstructions )
        {
            InstructionData *pDecData = entryPoint.m_Code.get( m_dwIP );

            // execute primitive
            if( m_pDbgEvents ) m_pDbgEvents->beforeExecPrimitive( this, *pDecData );

            //exec_primitive_fast( *pDecData ); // no run time checks in this version.
            if( ( iRet = exec_primitive( *pDecData ) ) != XORT_OK )
            {
                DebugMessage( "INTERNAL ERROR (dec mode): %d, function: '%s' IP: %06u, instr: %s, dumping stack:", iRet, entryPoint.m_csName.GetBuffer(), m_dwIP, pDecData->m_strInstr.GetBuffer() );
                if( m_pDbgEvents ) m_pDbgEvents->internalXVMError( this, iRet );
                DumpStack(); // just for debug
                return iRet;
            }

            m_pCurrentProc = &entryPoint; // update current procedure pointer
            m_dwExecutedPrimsCount++; // increment instruction counter

            if( m_pDbgEvents ) m_pDbgEvents->afterExecPrimitive( this, *pDecData, XORT_OK );

            if( m_dwFLAGS & XRTF_GOTO_EXECUTED ) {
                m_dwFLAGS = 0; // just reset flags, do not advance the IP, it is already done by jump instruction
            } else {
                if( pDecData->m_bInstrCode == p_ret )
                    break;
                m_dwIP += 1;
            }
        }

        //DebugMessage( "---> exit from function: %s", CONST_CHAR_PTR entryPoint.m_csName );
        //DebugMessage( "------------------------------------" );
    }

    m_dwCallsRecursionDepth--;
    if( m_pDbgEvents ) m_pDbgEvents->onLeaveSystemFrame( this, entryPoint );
    //DebugMessage( "---> Leaving function: '%s', status: [%d]", CONST_CHAR_PTR entryPoint.m_csName, iRet );
    m_pCurrentProc = NULL;
    return iRet;
}

int XRuntime::exec_primitive_fast( const InstructionData& primData )
{
    switch( primData.m_bInstrCode )
    {
    case p_addrof:   do_fast_addrof( primData ); break;
    case p_load:     do_fast_load( primData ); break;
    case p_mov:      do_fast_mov( primData ); break;
    case p_store:    do_fast_store( primData ); break;
    case p_drop:     do_fast_drop( primData ); break;
    case p_dup:      do_fast_dup( primData ); break;
    case p_swap:     do_fast_swap( primData ); break;
    case p_or:       do_fast_arith( primData, &arith_or ); break;
    case p_xor:      do_fast_arith( primData, &arith_xor ); break;
    case p_and:      do_fast_arith( primData, &arith_and ); break;
    case p_shl:      do_fast_arith( primData, &arith_shl ); break;
    case p_shr:      do_fast_arith( primData, &arith_shr ); break;
    case p_add:      do_fast_arith( primData, &arith_add ); break;
    case p_sub:      do_fast_arith( primData, &arith_sub ); break;
    case p_mul:      do_fast_arith( primData, &arith_mul ); break;
    case p_div:      do_fast_arith( primData, &arith_div ); break;
    case p_mod:      do_fast_arith( primData, &arith_mod ); break;
    case p_inc:      do_fast_unary_prim( primData, &const_inc ); break;
    case p_dec:      do_fast_unary_prim( primData, &const_dec ); break;
    case p_neg:      do_fast_unary_prim( primData, &const_neg ); break;
    case p_not:      do_fast_unary_prim( primData, &const_not ); break;
    case p_nz:       do_fast_nz( primData ); break;
    case p_lor:      do_fast_logical_op( primData, &const_lor ); break;
    case p_land:     do_fast_logical_op( primData, &const_land ); break;
    case p_lnot:     do_fast_unary_prim( primData, &const_lnot ); break;
    case p_cmpeq:    do_fast_logical_op( primData, &const_cmpeq ); break;
    case p_cmpneq:   do_fast_logical_op( primData, &const_cmpneq ); break;
    case p_cmpgt:    do_fast_logical_op( primData, &const_cmpgt ); break;
    case p_cmplt:    do_fast_logical_op( primData, &const_cmplt ); break;
    case p_cmpge:    do_fast_logical_op( primData, &const_cmpge ); break;
    case p_cmple:    do_fast_logical_op( primData, &const_cmple ); break;
    case p_convert:  do_fast_convert( primData ); break;
    case p_goto:     do_fast_goto( primData ); break;
    case p_ifz:      do_fast_ifz_nz( primData, &const_ifz ); break;
    case p_ifnz:     do_fast_ifz_nz( primData, &const_ifnz ); break;
    case p_ifeq:     do_fast_if_xx( primData, &const_cmpeq ); break;
    case p_ifneq:    do_fast_if_xx( primData, &const_cmpneq ); break;
    case p_ifleq:    do_fast_if_xx( primData, &const_cmple ); break;
    case p_ifgeq:    do_fast_if_xx( primData, &const_cmpge ); break;
    case p_ifg:      do_fast_if_xx( primData, &const_cmpgt ); break;
    case p_ifl:      do_fast_if_xx( primData, &const_cmplt ); break;
    case p_calli:    do_fast_calli( primData ); break;
    case p_call:     do_fast_call( primData ); break;
    case p_ret:      do_fast_ret( primData ); break;
    case p_new:      do_fast_new( primData ); break;
    case p_get:      do_fast_get( primData ); break;
    case p_put:      do_fast_put( primData ); break;
    case p_invoke:   do_fast_invoke( primData ); break;
    case p_gettype:  do_fast_gettype( primData ); break;
    case p_enter:    do_fast_enter( primData ); break;
    case p_leave:    do_fast_leave( primData ); break;
    case p_nop:      do_fast_nop( primData ); break;
    case p_dbgbreak: do_fast_dbgbreak( primData ); break;
    case p_pack:     do_fast_pack( primData ); break;
    case p_upack:    do_fast_upack( primData ); break;
    case p_stkvar:   break; // ignore pesudo instruction
    case p_label:    break; // ignore pesudo instruction
    }
    return XORT_OK;
}

int XRuntime::exec_primitive( const InstructionData& primData )
{
    switch( primData.m_bInstrCode )
    {
    case p_addrof:  m_dwExecPrimsCounter[p_addrof]    += 1;   return do_addrof( primData );
    case p_load:    m_dwExecPrimsCounter[p_load]      += 1;   return do_load( primData );
    case p_mov:     m_dwExecPrimsCounter[p_mov]       += 1;   return do_mov( primData );
    case p_store:   m_dwExecPrimsCounter[p_store]     += 1;   return do_store( primData );
    case p_drop:    m_dwExecPrimsCounter[p_drop]      += 1;   return do_drop( primData );
    case p_dup:     m_dwExecPrimsCounter[p_dup]       += 1;   return do_dup( primData );
    case p_swap:    m_dwExecPrimsCounter[p_swap]      += 1;   return do_swap( primData );
    case p_or:      m_dwExecPrimsCounter[p_or]        += 1;   return do_arith( primData, &arith_or );
    case p_xor:     m_dwExecPrimsCounter[p_xor]       += 1;   return do_arith( primData, &arith_xor );
    case p_and:     m_dwExecPrimsCounter[p_and]       += 1;   return do_arith( primData, &arith_and );
    case p_shl:     m_dwExecPrimsCounter[p_shl]       += 1;   return do_arith( primData, &arith_shl );
    case p_shr:     m_dwExecPrimsCounter[p_shr]       += 1;   return do_arith( primData, &arith_shr );
    case p_add:     m_dwExecPrimsCounter[p_add]       += 1;   return do_arith( primData, &arith_add );
    case p_sub:     m_dwExecPrimsCounter[p_sub]       += 1;   return do_arith( primData, &arith_sub );
    case p_mul:     m_dwExecPrimsCounter[p_mul]       += 1;   return do_arith( primData, &arith_mul );
    case p_div:     m_dwExecPrimsCounter[p_div]       += 1;   return do_arith( primData, &arith_div );
    case p_mod:     m_dwExecPrimsCounter[p_mod]       += 1;   return do_arith( primData, &arith_mod );
    case p_inc:     m_dwExecPrimsCounter[p_inc]       += 1;   return do_unary_prim( primData, &const_inc );
    case p_dec:     m_dwExecPrimsCounter[p_dec]       += 1;   return do_unary_prim( primData, &const_dec );
    case p_neg:     m_dwExecPrimsCounter[p_neg]       += 1;   return do_unary_prim( primData, &const_neg );
    case p_not:     m_dwExecPrimsCounter[p_not]       += 1;   return do_unary_prim( primData, &const_not );
    case p_nz:      m_dwExecPrimsCounter[p_nz]        += 1;   return do_nz( primData );
    case p_lor:     m_dwExecPrimsCounter[p_lor]       += 1;   return do_logical_op( primData, &const_lor );
    case p_land:    m_dwExecPrimsCounter[p_land]      += 1;   return do_logical_op( primData, &const_land );
    case p_lnot:    m_dwExecPrimsCounter[p_lnot]      += 1;   return do_unary_prim( primData, &const_lnot );
    case p_cmpeq:   m_dwExecPrimsCounter[p_cmpeq]     += 1;   return do_logical_op( primData, &const_cmpeq );
    case p_cmpneq:  m_dwExecPrimsCounter[p_cmpneq]    += 1;   return do_logical_op( primData, &const_cmpneq );
    case p_cmpgt:   m_dwExecPrimsCounter[p_cmpgt]     += 1;   return do_logical_op( primData, &const_cmpgt );
    case p_cmplt:   m_dwExecPrimsCounter[p_cmplt]     += 1;   return do_logical_op( primData, &const_cmplt );
    case p_cmpge:   m_dwExecPrimsCounter[p_cmpge]     += 1;   return do_logical_op( primData, &const_cmpge );
    case p_cmple:   m_dwExecPrimsCounter[p_cmple]     += 1;   return do_logical_op( primData, &const_cmple );
    case p_convert: m_dwExecPrimsCounter[p_convert]   += 1;   return do_convert( primData );
    case p_goto:    m_dwExecPrimsCounter[p_goto]      += 1;   return do_goto( primData );
    case p_ifz:     m_dwExecPrimsCounter[p_ifz]       += 1;   return do_ifz_nz( primData, &const_ifz );
    case p_ifnz:    m_dwExecPrimsCounter[p_ifnz]      += 1;   return do_ifz_nz( primData, &const_ifnz );
    case p_ifeq:    m_dwExecPrimsCounter[p_ifeq]      += 1;   return do_if_xx( primData, &const_cmpeq );
    case p_ifneq:   m_dwExecPrimsCounter[p_ifneq]     += 1;   return do_if_xx( primData, &const_cmpneq );
    case p_ifleq:   m_dwExecPrimsCounter[p_ifleq]     += 1;   return do_if_xx( primData, &const_cmple );
    case p_ifgeq:   m_dwExecPrimsCounter[p_ifgeq]     += 1;   return do_if_xx( primData, &const_cmpge );
    case p_ifg:     m_dwExecPrimsCounter[p_ifg]       += 1;   return do_if_xx( primData, &const_cmpgt );
    case p_ifl:     m_dwExecPrimsCounter[p_ifl]       += 1;   return do_if_xx( primData, &const_cmplt );
    case p_calli:   m_dwExecPrimsCounter[p_calli]     += 1;   return do_calli( primData );
    case p_call:    m_dwExecPrimsCounter[p_call]      += 1;   return do_call( primData );
    case p_ret:     m_dwExecPrimsCounter[p_ret]       += 1;   return do_ret( primData );
    case p_new:     m_dwExecPrimsCounter[p_new]       += 1;   return do_new( primData );
    case p_get:     m_dwExecPrimsCounter[p_get]       += 1;   return do_get( primData );
    case p_put:     m_dwExecPrimsCounter[p_put]       += 1;   return do_put( primData );
    case p_invoke:  m_dwExecPrimsCounter[p_invoke]    += 1;   return do_invoke( primData );
    case p_gettype: m_dwExecPrimsCounter[p_gettype]   += 1;   return do_gettype( primData );
    case p_enter:   m_dwExecPrimsCounter[p_enter]     += 1;   return do_enter( primData );
    case p_leave:   m_dwExecPrimsCounter[p_leave]     += 1;   return do_leave( primData );
    case p_nop:     m_dwExecPrimsCounter[p_nop]       += 1;   return do_nop( primData );
    case p_dbgbreak:m_dwExecPrimsCounter[p_dbgbreak]  += 1;   return do_dbgbreak( primData );
    case p_pack:    m_dwExecPrimsCounter[p_pack]      += 1;   return do_pack( primData );
    case p_upack:   m_dwExecPrimsCounter[p_upack]     += 1;   return do_upack( primData );
    case p_stkvar:  m_dwExecPrimsCounter[p_stkvar]    += 1;   return XORT_OK;
    case p_label:   m_dwExecPrimsCounter[p_label]     += 1;   return do_label( primData );
    }
    return ERR_UNKNOWN_PRIMCODE;
}

int XRuntime::do_addrof( const InstructionData& primData )
{
    // Instruction is redundant. There is no reason to implement it.
    return ERR_PRIMITIVE_NOTIMPL;
}
int XRuntime::do_load( const InstructionData& primData )
{
    byte bCmdType = primData.m_bTypeAddr & 0xF0;

    switch( primData.m_bTypeAddr & 0x0F )
    {
    case a_c:
        {
            if( primData.m_Value.bType != bCmdType ) return ERR_INVALID_PRIMCODE;
            const_cast<InstructionData&>( primData ).m_Value.bAccess = usr_VarRW;
            m_Stack.push( primData.m_Value ); 
            break;
        }
    case a_m: 
        {
            if( primData.m_Value.bType != t_u4 ) return ERR_INVALID_PRIMCODE;
            if( !m_Data.canGet( primData.m_Value._u4 ) ) return ERR_INVALID_DATA_IDX;
            XortElement x = m_Data.get( primData.m_Value._u4 );
            if( x.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            m_Stack.push( x );
            break;
        }
    case a_s:
        {
            if( primData.m_Value.bType != t_s2 ) return ERR_INVALID_PRIMCODE;
            int iIdx = (int)m_dwStackBase + primData.m_Value._s2;
            if( !m_Stack.canGet( (dword)iIdx ) ) return ERR_INVALID_STACK_IDX;
            XortElement x = m_Stack.get( (dword)iIdx );
            if( x.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            m_Stack.push( x );
            break;
        }
    case a_indm: 
        {
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            XortElement x = m_Stack.pop();
            if( x.bType != t_u4 ) return ERR_INVALID_TYPE;
            if( !m_Data.canGet( x._u4 ) ) return ERR_INVALID_DATA_IDX;
            XortElement m = m_Data.get( x._u4 );
            if( m.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            m.bAccess = usr_VarRW; //-change the access type, as it is now on arith stack
            m_Stack.push( m );
            break;
        }
    case a_inds:
        {
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            XortElement x = m_Stack.pop();
            if( x.bType != t_s2 ) return ERR_INVALID_TYPE;
            int iIdx = (int)m_dwStackBase + x._s2;
            if( !m_Stack.canGet( (dword)iIdx ) ) return ERR_INVALID_STACK_IDX;
            XortElement s = m_Stack.get( (dword)iIdx );
            if( s.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            s.bAccess = usr_VarRW;
            m_Stack.push( s );
            break;
        }
    case a_ti:
        {
            if( primData.m_Value.bType != t_u2 ) return ERR_INVALID_PRIMCODE;
            if( !m_Stack.canGet( m_dwStackBase ) ) return ERR_INVALID_STACK_IDX;
            XortElement& sysFr = m_Stack.get( m_dwStackBase );
            if( !( sysFr.bAccess & sys_Frame ) ) return ERR_INVALID_STACK_SYSFRAME;
            if( sysFr._ti == 0 ) return ERR_THIS_PTR_NULL;
            xobject *pObj = (xobject *)sysFr._ti;
            XortElement x;
            int iRet = pObj->Get( primData.m_Value._u2, x );
            if( iRet != XORT_OK ) return iRet;
            if( x.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            x.bAccess = usr_VarRW;
            m_Stack.push( x );
            break;
        }
    default:
        return ERR_INVALID_PRIMCODE;
    }

    return XORT_OK;
}   
int XRuntime::do_mov( const InstructionData& primData )
{
    byte bCmdType = primData.m_bTypeAddr & 0xF0;
    byte bAddr    = primData.m_bTypeAddr & 0x0F;
    int iOffset;

    switch( bAddr )
    {
    case a_cs:    // mov.cs.T   S[#] = c
        {
            if( primData.m_Value.bType != t_s2 || primData.m_Value2.bType != bCmdType ) return ERR_INVALID_PRIMCODE;
            iOffset = (int)m_dwStackBase + primData.m_Value._s2;
            if( !m_Stack.canGet( (dword)iOffset ) ) return ERR_INVALID_STACK_IDX;
            XortElement& v1 = m_Stack.get( (dword)iOffset );
            if( !( v1.bAccess  & usr_VarRW ) ) return ERR_INVALID_ACCESS;
            if( v1.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            v1 = primData.m_Value2;
            break;
        }
    case a_cm:    // mov.cm.T   M[#] = c
        {
            if( primData.m_Value.bType != t_u4 || primData.m_Value2.bType != bCmdType ) return ERR_INVALID_PRIMCODE;
            if( !m_Data.canGet( primData.m_Value._u4 ) ) return ERR_INVALID_DATA_IDX;
            XortElement& v1 = m_Data.get( primData.m_Value._u4 );
            if( !( v1.bAccess  & usr_VarRW ) ) return ERR_INVALID_ACCESS;
            if( v1.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            v1 = primData.m_Value2;
            break;
        }
    case a_ms:    // mov.ms.T   S[#] = M[#]
        {
            if( primData.m_Value.bType != t_s2 || primData.m_Value2.bType != t_u4 ) return ERR_INVALID_PRIMCODE;
            iOffset = (int)m_dwStackBase + primData.m_Value._s2;
            if( !m_Stack.canGet( (dword)iOffset ) ) return ERR_INVALID_STACK_IDX;
            XortElement& v1 = m_Stack.get( (dword)iOffset );
            if( !m_Data.canGet( primData.m_Value2._u4 ) ) return ERR_INVALID_DATA_IDX;
            XortElement& v2 = m_Data.get( primData.m_Value2._u4 );
            if( !( v1.bAccess  & usr_VarRW ) || !( v2.bAccess & usr_VarR ) ) return ERR_INVALID_ACCESS;
            if( v1.bType != bCmdType || v2.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            v1 = v2;
            break;
        }
    case a_sm:    // mov.sm.T   M[#] = S[#]
        {
            if( primData.m_Value.bType != t_u4 || primData.m_Value2.bType != t_s2 ) return ERR_INVALID_PRIMCODE;
            iOffset = (int)m_dwStackBase + primData.m_Value2._s2;
            if( !m_Stack.canGet( (dword)iOffset ) ) return ERR_INVALID_STACK_IDX;
            XortElement& v2 = m_Stack.get( (dword)iOffset );
            if( !m_Data.canGet( primData.m_Value._u4 ) ) return ERR_INVALID_DATA_IDX;
            XortElement& v1 = m_Data.get( primData.m_Value._u4 );
            if( !( v1.bAccess  & usr_VarRW ) || !( v2.bAccess & usr_VarR ) ) return ERR_INVALID_ACCESS;
            if( v1.bType != bCmdType || v2.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            v1 = v2;
            break;
        }
    case a_ss:    // mov.ss.T   S[#] = S[#]
        {
            if( primData.m_Value.bType != t_s2 || primData.m_Value2.bType != t_s2 ) return ERR_INVALID_PRIMCODE;
            iOffset = (int)m_dwStackBase + primData.m_Value2._s2;
            if( !m_Stack.canGet( (dword)iOffset ) ) return ERR_INVALID_STACK_IDX;
            XortElement& v2 = m_Stack.get( (dword)iOffset );
            iOffset = (int)m_dwStackBase + primData.m_Value._s2;
            if( !m_Stack.canGet( (dword)iOffset ) ) return ERR_INVALID_STACK_IDX;
            XortElement& v1 = m_Stack.get( (dword)iOffset );
            if( !( v1.bAccess  & usr_VarRW ) || !( v2.bAccess & usr_VarR ) ) return ERR_INVALID_ACCESS;
            if( v1.bType != bCmdType || v2.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            v1 = v2;
            break;
        }
    case a_mm:    // mov.mm.T   M[#] = M[#]
        {
            if( primData.m_Value.bType != t_u4 || primData.m_Value2.bType != t_u4 ) return ERR_INVALID_PRIMCODE;
            if( !m_Data.canGet( primData.m_Value._u4 ) ) return ERR_INVALID_DATA_IDX;
            XortElement& v1 = m_Data.get( primData.m_Value._u4 );
            if( !m_Data.canGet( primData.m_Value2._u4 ) ) return ERR_INVALID_DATA_IDX;
            XortElement& v2 = m_Data.get( primData.m_Value2._u4 );
            if( !( v1.bAccess  & usr_VarRW ) || !( v2.bAccess & usr_VarR ) ) return ERR_INVALID_ACCESS;
            if( v1.bType != bCmdType || v2.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            v1 = v2;
            break;
        }
    default: return ERR_INVALID_PRIMCODE;
    }

    return XORT_OK; 
}
int XRuntime::do_store( const InstructionData& primData )
{
    int iRet = XORT_OK;
    byte bCmdType = primData.m_bTypeAddr & 0xF0;

    switch( primData.m_bTypeAddr & 0x0F )
    {
    case a_m: 
        {
            if( primData.m_Value.bType != t_u4 ) return ERR_INVALID_PRIMCODE;
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            XortElement x = m_Stack.pop();
            if( !m_Data.canGet( primData.m_Value._u4 ) ) return ERR_INVALID_DATA_IDX;
            XortElement& m = m_Data.get( primData.m_Value._u4 );
            if( m.bType != x.bType ) return ERR_TYPES_MISMATCH;
            m = x;
            break;
        }
    case a_s:
        {
            if( primData.m_Value.bType != t_s2 ) return ERR_INVALID_PRIMCODE;
            int iIdx = (int)m_dwStackBase + primData.m_Value._s2;
            if( !m_Stack.canGet( (dword)iIdx ) ) return ERR_INVALID_STACK_IDX;
            XortElement& x = m_Stack.get( (dword)iIdx );
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            XortElement t = m_Stack.pop();
            if( x.bType != t.bType ) return ERR_TYPES_MISMATCH;
            x = t;
            break;
        }
    case a_indm: 
        {
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            XortElement x = m_Stack.pop();
            if( x.bType != t_u4 ) return ERR_INVALID_TYPE;
            if( !m_Data.canGet( x._u4 ) ) return ERR_INVALID_DATA_IDX;
            XortElement& m = m_Data.get( x._u4 );
            if( m.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            XortElement t = m_Stack.pop();
            if( m.bType != t.bType ) return ERR_TYPES_MISMATCH;
            m = t;
            break;
        }
    case a_inds:
        {
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            XortElement x = m_Stack.pop();
            if( x.bType != t_s2 ) return ERR_INVALID_TYPE;
            int iIdx = (int)m_dwStackBase + x._s2;
            if( !m_Stack.canGet( (dword)iIdx ) ) return ERR_INVALID_STACK_IDX;
            XortElement& s = m_Stack.get( (dword)iIdx );
            if( s.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            XortElement t = m_Stack.pop();
            if( s.bType != t.bType ) return ERR_TYPES_MISMATCH;
            s = t;
            break;
        }
    case a_ti:
        {
            if( primData.m_Value.bType != t_u2 ) return ERR_INVALID_PRIMCODE;
            if( !m_Stack.canGet( m_dwStackBase ) ) return ERR_INVALID_STACK_IDX;
            XortElement& sysFr = m_Stack.get( m_dwStackBase );
            if( !( sysFr.bAccess & sys_Frame ) ) return ERR_INVALID_STACK_SYSFRAME;
            if( sysFr._ti == 0 ) return ERR_THIS_PTR_NULL;
            xobject *pObj = (xobject *)sysFr._ti;
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            XortElement x = m_Stack.pop();
            if( x.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            iRet = pObj->Put( primData.m_Value._u2, x );
            break;
        }
    default:
        return ERR_INVALID_PRIMCODE;
    }

    return iRet;
}
int XRuntime::do_drop( const InstructionData& primData )
{
    if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
    XortElement x = m_Stack.pop();
    if( x.bAccess & sys_Frame ) return ERR_STACK_UNDERFLOW;
    return XORT_OK; 
}   
int XRuntime::do_dup( const InstructionData& primData )
{
    if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
    XortElement x = m_Stack.top();
    if( x.bAccess & sys_Frame ) return ERR_INVALID_ACCESS;
    m_Stack.push( x );
    return XORT_OK; 
}    
int XRuntime::do_swap( const InstructionData& primData )
{
    if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
    XortElement x = m_Stack.top();
    if( x.bAccess & sys_Frame ) return ERR_INVALID_ACCESS;
    dword dwCount = m_Stack.count();
    if( !m_Stack.canGet( (dword)dwCount-2 ) ) return ERR_INVALID_STACK_IDX;
    if( !m_Stack.canPut( dwCount-1 ) ) return ERR_INVALID_STACK_IDX;
    m_Stack.put( dwCount-1, m_Stack.get( dwCount-2 ) );
    if( !m_Stack.canPut( dwCount-2 ) ) return ERR_INVALID_STACK_IDX;
    m_Stack.put( dwCount-2, x );
    return XORT_OK; 
}   
int XRuntime::do_arith( const InstructionData& primData, _lopfn_t *pfn )
{ 
    XortElement v1, v2, vRes;
    int iRet, iOffset;
    xobject *pObj;

    byte bCmdType = primData.m_bTypeAddr & 0xF0;
    byte bAddr    = primData.m_bTypeAddr & 0x0F;

    switch( bAddr )
    {
    case 0:     // add.T	v1, v2 -> v1 + v2
        {
            if ( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            v2 = m_Stack.pop();
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            v1 = m_Stack.pop();
            if( !( v1.bAccess & usr_VarRW ) || !( v2.bAccess & usr_VarRW ) ) return ERR_INVALID_ACCESS;
            if( v1.bType != bCmdType || v2.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            if( ( iRet = pfn( v1, v2, vRes ) ) == XORT_OK ) m_Stack.push( vRes );
            break;
        }   
    case a_c:   // add.c.T	v1 -> v1 + c
        {
            v2 = primData.m_Value;
            if( v2.bType != bCmdType ) return ERR_INVALID_PRIMCODE;
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            v1 = m_Stack.pop();
            if( !( v1.bAccess & usr_VarRW ) ) return ERR_INVALID_ACCESS;
            if( v1.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            if( ( iRet = pfn( v1, v2, vRes ) ) == XORT_OK ) m_Stack.push( vRes );
            break;
        }
    case a_m:   // add.m.T	v1 -> v1 + M[#]
        {
            if( primData.m_Value.bType != bCmdType ) return ERR_INVALID_PRIMCODE;
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            v1 = m_Stack.pop();
            if( !m_Data.canGet( primData.m_Value._u4 ) ) return ERR_INVALID_DATA_IDX;
            v2 = m_Data.get( primData.m_Value._u4 );
            if( !( v1.bAccess & usr_VarRW ) || !( v2.bAccess & usr_VarR ) ) return ERR_INVALID_ACCESS;
            if( v1.bType != bCmdType || v1.bType != v2.bType ) return ERR_TYPES_MISMATCH;
            if( ( iRet = pfn( v1, v2, vRes ) ) == XORT_OK ) m_Stack.push( vRes );
            break;
        }
    case a_s:   // add.s.T	v1 -> v1 + S[#]
        {
            if( primData.m_Value.bType != t_s2 ) return ERR_INVALID_PRIMCODE;
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            v1 = m_Stack.pop();
            iOffset = (int)m_dwStackBase + primData.m_Value._s2;
            if ( !m_Stack.canGet( (dword)iOffset ) ) return ERR_INVALID_STACK_IDX;
            v2 = m_Stack.get( (dword)iOffset );
            if( !( v1.bAccess & usr_VarRW ) || !( v2.bAccess & usr_VarR ) ) return ERR_INVALID_ACCESS;
            if( v1.bType != bCmdType || v1.bType != v2.bType ) return ERR_TYPES_MISMATCH;
            if( ( iRet = pfn( v1, v2, vRes ) ) == XORT_OK ) m_Stack.push( vRes );
            break;
        }
    case a_indm: return ERR_INVALID_PRIMCODE;
    case a_inds: return ERR_INVALID_PRIMCODE;
    case a_cs:  // add.cs.T	S[#] += c
        {
            if( primData.m_Value.bType != t_s2 || primData.m_Value2.bType != bCmdType ) return ERR_INVALID_PRIMCODE;
            iOffset = (int)m_dwStackBase + primData.m_Value._s2;
            if( !m_Stack.canGet( (dword)iOffset ) ) return ERR_INVALID_STACK_IDX;
            v1 = m_Stack.get( (dword)iOffset );
            v2 = primData.m_Value2;
            if( !( v1.bAccess  & usr_VarRW ) ) return ERR_INVALID_ACCESS;
            if( v1.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            if( ( iRet = pfn( v1, v2, vRes ) ) == XORT_OK ) m_Stack.put( iOffset, vRes );
            break;
        }
    case a_cm:  // add.cm.T	M[#] += c
        {
            if( primData.m_Value.bType != t_u4 || primData.m_Value2.bType != bCmdType ) return ERR_INVALID_PRIMCODE;
            if( !m_Data.canGet( primData.m_Value._u4 ) ) return ERR_INVALID_DATA_IDX;
            v1 = m_Data.get( primData.m_Value._u4 );
            v2 = primData.m_Value2;
            if( !( v1.bAccess  & usr_VarRW ) ) return ERR_INVALID_ACCESS;
            if( v1.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            if( ( iRet = pfn( v1, v2, vRes ) ) == XORT_OK ) m_Data.put( primData.m_Value._u4, vRes );
            break;
        }
    case a_ms:  // add.ms.T	S[#] += M[#]
        {
            if( primData.m_Value.bType != t_s2 || primData.m_Value2.bType != t_u4 ) return ERR_INVALID_PRIMCODE;
            iOffset = (int)m_dwStackBase + primData.m_Value._s2;
            if( !m_Stack.canGet( (dword)iOffset ) ) return ERR_INVALID_STACK_IDX;
            v1 = m_Stack.get( (dword)iOffset );
            if( !m_Data.canGet( primData.m_Value2._u4 ) ) return ERR_INVALID_DATA_IDX;
            v2 = m_Data.get( primData.m_Value2._u4 );
            if( !( v1.bAccess  & usr_VarRW ) || !( v2.bAccess & usr_VarR ) ) return ERR_INVALID_ACCESS;
            if( v1.bType != bCmdType || v2.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            if( ( iRet = pfn( v1, v2, vRes ) ) == XORT_OK ) m_Stack.put( (dword)iOffset, vRes );
            break;
        }
    case a_sm:  // add.sm.T	M[#] += S[#]
        {
            if( primData.m_Value.bType != t_u4 || primData.m_Value2.bType != t_s2 ) return ERR_INVALID_PRIMCODE;
            iOffset = (int)m_dwStackBase + primData.m_Value2._s2;
            if( !m_Stack.canGet( (dword)iOffset ) ) return ERR_INVALID_STACK_IDX;
            v2 = m_Stack.get( (dword)iOffset );
            if( !m_Data.canGet( primData.m_Value._u4 ) ) return ERR_INVALID_DATA_IDX;
            v1 = m_Data.get( primData.m_Value._u4 );
            if( !( v1.bAccess  & usr_VarRW ) || !( v2.bAccess & usr_VarR ) ) return ERR_INVALID_ACCESS;
            if( v1.bType != bCmdType || v2.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            if( ( iRet = pfn( v1, v2, vRes ) ) == XORT_OK ) m_Data.put( primData.m_Value._u4, vRes );
            break;
        }
    case a_ss:  // add.ss.T	S[#] += S[#]
        {
            if( primData.m_Value.bType != t_s2 || primData.m_Value2.bType != t_s2 ) return ERR_INVALID_PRIMCODE;
            iOffset = (int)m_dwStackBase + primData.m_Value2._s2;
            if( !m_Stack.canGet( (dword)iOffset ) ) return ERR_INVALID_STACK_IDX;
            v2 = m_Stack.get( (dword)iOffset );
            iOffset = (int)m_dwStackBase + primData.m_Value._s2;
            if( !m_Stack.canGet( (dword)iOffset ) ) return ERR_INVALID_STACK_IDX;
            v1 = m_Stack.get( (dword)iOffset );
            if( !( v1.bAccess  & usr_VarRW ) || !( v2.bAccess & usr_VarR ) ) return ERR_INVALID_ACCESS;
            if( v1.bType != bCmdType || v2.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            if( ( iRet = pfn( v1, v2, vRes ) ) == XORT_OK ) m_Stack.put( (dword)iOffset, vRes );
            break;
        }
    case a_mm:  // add.mm.T	M[#] += M[#]
        {
            if( primData.m_Value.bType != t_u4 || primData.m_Value2.bType != t_u4 ) return ERR_INVALID_PRIMCODE;
            if( !m_Data.canGet( primData.m_Value._u4 ) ) return ERR_INVALID_DATA_IDX;
            v1 = m_Data.get( primData.m_Value._u4 );
            if( !m_Data.canGet( primData.m_Value2._u4 ) ) return ERR_INVALID_DATA_IDX;
            v2 = m_Data.get( primData.m_Value2._u4 );
            if( !( v1.bAccess  & usr_VarRW ) || !( v2.bAccess & usr_VarR ) ) return ERR_INVALID_ACCESS;
            if( v1.bType != bCmdType || v2.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            if( ( iRet = pfn( v1, v2, vRes ) ) == XORT_OK ) m_Data.put( primData.m_Value._u4, vRes );
            break;
        }
    case a_ma:  iRet = ERR_INVALID_PRIMCODE; break;
    case a_sa:  iRet = ERR_INVALID_PRIMCODE; break;
    case a_ta:  iRet = ERR_INVALID_PRIMCODE; break;
    case a_ti:  // v1 -> v1 + T[#] 
        {
            if( primData.m_Value.bType != t_u2 ) return ERR_INVALID_PRIMCODE;
            if( !m_Stack.canGet( m_dwStackBase ) ) return ERR_INVALID_STACK_IDX;
            XortElement& sysFr = m_Stack.get( m_dwStackBase );
            if( !( sysFr.bAccess & sys_Frame ) ) return ERR_INVALID_STACK_SYSFRAME;
            if( sysFr._ti == 0 ) return ERR_THIS_PTR_NULL;
            pObj = (xobject *)sysFr._ti;
            iRet = pObj->Get( primData.m_Value._u2, v2 );
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            v1 = m_Stack.pop();
            if( !( v1.bAccess  & usr_VarRW ) || !( v2.bAccess & usr_VarR ) ) return ERR_INVALID_ACCESS;
            if( v1.bType != bCmdType || v2.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            if( ( iRet = pfn( v1, v2, vRes ) ) == XORT_OK ) m_Data.put( primData.m_Value._u4, vRes );
            break;
        }
    default: iRet = ERR_INVALID_PRIMCODE; break;
    }

    return iRet;
}
int XRuntime::do_unary_prim( const InstructionData& primData, _opfn_t *pfn )
{
    int iRet;
    byte bCmdType = primData.m_bTypeAddr & 0xF0;

    switch( primData.m_bTypeAddr & 0x0F )
    {
    case t_v:
        {
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            XortElement& x = m_Stack.top();
            if( x.bAccess != usr_VarRW ) return ERR_INVALID_ACCESS;
            if( x.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            iRet = pfn( x );
            break;
        }
    case a_m:
        {
            if( primData.m_Value.bType != t_u4 ) return ERR_INVALID_PRIMCODE;
            if( !m_Data.canGet( primData.m_Value._u4 ) ) return ERR_INVALID_DATA_IDX;
            XortElement& x = m_Data.get( primData.m_Value._u4 );
            if( x.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            iRet = pfn( x );
            break;
        }
    case a_s:
        {
            if( primData.m_Value.bType != t_s2 ) return ERR_INVALID_PRIMCODE;
            int iIdx = (int)m_dwStackBase + primData.m_Value._s2;
            if( !m_Stack.canGet( (dword)iIdx ) ) return ERR_INVALID_STACK_IDX;
            XortElement& x = m_Stack.get( (dword)iIdx );
            if( x.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            iRet = pfn( x );
            break;
        }
    case a_ti:
        {
            if( primData.m_Value.bType != t_u2 ) return ERR_INVALID_PRIMCODE;
            if( !m_Stack.canGet( m_dwStackBase ) ) return ERR_INVALID_STACK_IDX;
            XortElement& sysFr = m_Stack.get( m_dwStackBase );
            if( !( sysFr.bAccess & sys_Frame ) ) return ERR_INVALID_STACK_SYSFRAME;
            if( sysFr._ti == 0 ) return ERR_THIS_PTR_NULL;
            xobject *pObj = (xobject *)sysFr._ti;
            XortElement v;
            iRet = pObj->Get( primData.m_Value._u2, v );
            if( iRet == XORT_OK ) {
                if( v.bAccess != usr_VarRW ) return ERR_INVALID_ACCESS;
                if( v.bType != bCmdType ) return ERR_TYPES_MISMATCH;
                iRet = pfn( v );
                if( iRet == XORT_OK ) {
                    iRet = pObj->Put( primData.m_Value._u2, v );
                }
            }
            break;
        }
    default:
        iRet = ERR_INVALID_ADDR;
        break;
    }
    
    return iRet;
}
int XRuntime::do_nz( const InstructionData& primData )
{
    if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
    XortElement x = m_Stack.pop();
    if( x.bAccess != usr_VarRW ) return ERR_INVALID_ACCESS;
    XortElement vRes;
    int iRet = const_nz( x, vRes );
    if( iRet == XORT_OK ) m_Stack.push( vRes );
    return iRet; 
}
int XRuntime::do_logical_op( const InstructionData& primData, _lopfn_t *pfn )
{   
    if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
    XortElement v2 = m_Stack.pop();
    if( v2.bAccess != usr_VarRW ) return ERR_INVALID_ACCESS;
    if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
    XortElement v1 = m_Stack.pop();
    if( v1.bAccess != usr_VarRW ) return ERR_INVALID_ACCESS;
    XortElement vRes;
    int iRet = pfn( v1, v2, vRes );
    if( iRet == XORT_OK ) m_Stack.push( vRes );
    return XORT_OK; 
}
int XRuntime::do_convert( const InstructionData& primData )
{
    XortElement& x = m_Stack.top();
    if( x.bAccess != usr_VarRW ) return ERR_INVALID_ACCESS;
    byte bSrcType = ( primData.m_bTypeAddr & 0x0F ) << 4;
    byte bDstType = primData.m_bTypeAddr & 0xF0;
    if( bSrcType != x.bType ) 
        return ERR_TYPES_MISMATCH;

    XortElement n;
    int iRet = x_convert_type( bDstType, n, x );
    if( iRet == XORT_OK ) {
        x.bType = bDstType;
        x._u8 = n._u8;
    }

    return iRet;
}
int XRuntime::do_goto( const InstructionData& primData )
{
    byte bType = primData.m_bTypeAddr & 0xF0;
    int iOffset;

    switch( bType )
    { 
    case t_s1: iOffset = primData.m_Value._s1; break;
    case t_s2: iOffset = primData.m_Value._s2; break;
    case t_s4: iOffset = primData.m_Value._s4; break;
    default: return ERR_INVALID_PRIMCODE;
    }

    applyOffsetIP( iOffset );

    return XORT_OK; 
}
int XRuntime::do_ifz_nz( const InstructionData& primData, _copfnifx *pfn )
{
    int iRet, iResult = 0;
    byte bCmdType = primData.m_bTypeAddr & 0xF0;
    byte bAddr    = primData.m_bTypeAddr & 0x0F;

    switch( bAddr )
    {
    case 0: // means operate on stack: value != 0 -> ...
        {
            if( primData.m_Value.bType != t_s2 ) return ERR_INVALID_PRIMCODE;
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            XortElement x = m_Stack.pop();
            if( !(x.bAccess & usr_VarR) ) return ERR_INVALID_ACCESS;
            if( x.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            if( ( ( iRet = pfn( x, iResult ) ) == XORT_OK ) && iResult ) applyOffsetIP( primData.m_Value._s2 );
            break;
        }
    case a_ma:  // M[#] != 0
        {
            if( primData.m_Value.bType != t_u4 || primData.m_Value2.bType != t_s2 ) return ERR_INVALID_PRIMCODE;
            if( !m_Data.canGet( primData.m_Value._u4 ) ) return ERR_INVALID_DATA_IDX;
            XortElement& x = m_Data.get( primData.m_Value._u4 );
            if( x.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            if( ( ( iRet = pfn( x, iResult ) ) == XORT_OK ) && iResult ) applyOffsetIP( primData.m_Value2._s2 );
            break;
        }
    case a_sa:  // S[#] != 0
        {
            if( primData.m_Value.bType != t_s2 || primData.m_Value2.bType != t_s2 ) return ERR_INVALID_PRIMCODE;
            int iIdx = (int)m_dwStackBase + primData.m_Value._s2;
            if( !m_Stack.canGet( (dword)iIdx ) ) return ERR_INVALID_STACK_IDX;
            XortElement& x = m_Stack.get( (dword)iIdx );
            if( x.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            if( ( ( iRet = pfn( x, iResult ) ) == XORT_OK ) && iResult ) applyOffsetIP( primData.m_Value2._s2 );
            break;
        }
    case a_ta:  // T[#] != 0 - not implemented in the compiler yet
        {
            if( primData.m_Value.bType != t_u2 || primData.m_Value2.bType != t_s2 ) return ERR_INVALID_PRIMCODE;
            if( !m_Stack.canGet( m_dwStackBase ) ) return ERR_INVALID_STACK_IDX;
            XortElement& sysFr = m_Stack.get( m_dwStackBase );
            if( !( sysFr.bAccess & sys_Frame ) ) return ERR_INVALID_STACK_SYSFRAME;
            if( sysFr._ti == 0 ) return ERR_THIS_PTR_NULL;
            xobject *pObj = (xobject *)sysFr._ti;
            XortElement v1;
            if( ( iRet = pObj->Get( primData.m_Value._u2, v1 ) ) == XORT_OK ) {
                if( !( v1.bAccess & usr_VarR ) ) return ERR_INVALID_ACCESS;
                if( v1.bType != bCmdType ) return ERR_TYPES_MISMATCH;
                if( ( iRet = pfn( v1, iResult ) ) == XORT_OK ) applyOffsetIP( primData.m_Value2._s2 );
            }
            break;
        }
    default: iRet = ERR_INVALID_PRIMCODE; break;
    }

    return iRet; 
}
int XRuntime::do_if_xx( const InstructionData& primData, _lopfn_t *pfn )
{ 
    int iRet;
    byte bCmdType  = primData.m_bTypeAddr & 0xF0;
    byte bAddr     = primData.m_bTypeAddr & 0x0F;
    XortElement v1, v2, vRes;
    int iOffset, iIdx;

    switch( bAddr )
    {
    case 0: // means operate on stack:      ifeq.T   v1, v2 == -> ...
        {
            if( primData.m_Value.bType != t_s2 ) return ERR_INVALID_PRIMCODE;
            iOffset = primData.m_Value._s2;
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            v2 = m_Stack.pop();
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            v1 = m_Stack.pop();
            break;
        }
    case a_ma:  // ifeq.ma.T    v1 == M[#] -> ...
        {
            if( primData.m_Value.bType != t_u4 || primData.m_Value2.bType != t_s2 ) return ERR_INVALID_PRIMCODE;
            iOffset = primData.m_Value2._s2;
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            v1 = m_Stack.pop();
            if( !m_Data.canGet( primData.m_Value._u4 ) ) return ERR_INVALID_DATA_IDX;
            v2 = m_Data.get( primData.m_Value._u4 );
            break;
        }
    case a_sa:  // ifeq.sa.T    v1 == S[#] -> ...
        {
            if( primData.m_Value.bType != t_s2 || primData.m_Value2.bType != t_s2 ) return ERR_INVALID_PRIMCODE;
            iOffset = primData.m_Value2._s2;
            iIdx = (int)m_dwStackBase + primData.m_Value._s2;
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            v1 = m_Stack.pop();
            if( !m_Stack.canGet( (dword)iIdx ) ) return ERR_INVALID_STACK_IDX;
            v2 = m_Stack.get( (dword)iIdx );
            break;
        }
    case a_ta:  // ifeq.ta.T    v1 == T[#] -> ...
        {
            if( primData.m_Value.bType != t_u2 || primData.m_Value2.bType != t_s2 ) return ERR_INVALID_PRIMCODE;
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            v1 = m_Stack.pop();
            if( !m_Stack.canGet( m_dwStackBase ) ) return ERR_INVALID_STACK_IDX;
            XortElement& sysFr = m_Stack.get( m_dwStackBase );
            if( !( sysFr.bAccess & sys_Frame ) ) return ERR_INVALID_STACK_SYSFRAME;
            if( sysFr._ti == 0 ) return ERR_THIS_PTR_NULL;
            xobject *pObj = (xobject *)sysFr._ti;
            if( ( iRet = pObj->Get( primData.m_Value._u2, v2 ) ) != XORT_OK ) return iRet;
            iOffset = primData.m_Value2._s2;
            break;
        }
    default: return ERR_INVALID_PRIMCODE;;
    }

    if( !( v1.bAccess & usr_VarR ) || !( v2.bAccess & usr_VarR ) ) return ERR_INVALID_ACCESS;
    if( v1.bType != bCmdType || v1.bType != v2.bType ) return ERR_TYPES_MISMATCH;
    if( ( ( iRet = pfn( v1, v2, vRes ) ) == XORT_OK ) && vRes._s4 )
        applyOffsetIP( iOffset );

    return iRet; 
}
int XRuntime::do_calli( const InstructionData& primData )
{
    if( primData.m_Value.bType != t_u4 ) return ERR_INVALID_TYPE;
    symbolref pFunc = m_Functions.get( primData.m_Value._u4 );
    dword dwFuncRetType = pFunc->m_dwType >= t_p ? t_p : pFunc->m_dwType; // align types
    if( primData.m_bTypeAddr != dwFuncRetType ) return ERR_TYPES_MISMATCH;

    XortElement x;
    x.bAccess = sys_Frame;
    if( pFunc->m_dwFlags & f_unspecnumargs ) { // apply the actual number of arguments for unspecified number of args
        if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
        XortElement argNo = m_Stack.pop();     // trick: we pop out the informational argument with the number of args
        if( argNo.bType != t_u1 ) return ERR_INVALID_TYPE;
        x.bType = argNo._u1;                   // and put the number of arguments into system frame
    } else {
        x.bType = pFunc->m_listMembers.size() - 1; // set number of arguments, skip localScope marker
    }

    x._ti = 0;
    x._asp = m_dwStackBase;             // save old stack base
    m_dwStackBase = m_Stack.push( x );  // create system frame

    // save current IP
    x.bType = t_u4; x.bAccess = sys_Frame; x._u4 = m_dwIP;
    m_RetStack.push( x );
   
    return Exec( *pFunc ); 
} 
int XRuntime::do_call( const InstructionData& primData )
{
    if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
    XortElement addr = m_Stack.pop();
    if( addr.bType != t_u4 ) return ERR_INVALID_PRIMCODE;

    symbolref pFunc = m_Functions.get( addr._u4 );
    if( primData.m_bTypeAddr != pFunc->m_dwType ) return ERR_TYPES_MISMATCH; // TODO: align types?

    XortElement x;
    x.bAccess = sys_Frame;
    if( pFunc->m_dwFlags & f_unspecnumargs ) { // apply the actual number of arguments for unspecified number of args
        if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
        XortElement argNo = m_Stack.pop();     // trick: we pop out the informational argument with the number of args
        if( argNo.bType != t_u1 ) return ERR_INVALID_TYPE;
        x.bType = argNo._u1;                   // and put the number of arguments into system frame
    } else {
        x.bType = pFunc->m_listMembers.size() - 1; // set number of arguments, skip localScope marker
    }

    x._ti = 0;
    x._asp = m_dwStackBase;             // save old stack base
    m_dwStackBase = m_Stack.push( x );  // create system frame

    // save current IP
    x.bType = t_u4; x.bAccess = sys_Frame; x._u4 = m_dwIP;
    m_RetStack.push( x );

    return Exec( *pFunc ); 
}
int XRuntime::do_ret( const InstructionData& primData )
{
    XortElement x;
    if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
    if( primData.m_bTypeAddr != t_v ) x = m_Stack.pop();

    // cleanup the stack till system frame
    int bBrake = FALSE;
    dword dwArgsCount = 0;
    do
    {
        if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
         XortElement xClean = m_Stack.pop();
         if( xClean.bAccess & sys_Frame ) {
             m_dwStackBase = xClean._asp;
             dwArgsCount = xClean.bType;   
             bBrake = TRUE;
         }
         xClean.Clear();
    } while( !bBrake );

    // remove arguments
    while( dwArgsCount ) {
        if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
        XortElement xClean = m_Stack.pop();
        xClean.Clear();
        dwArgsCount--;
    }

    if( primData.m_bTypeAddr != t_v ) m_Stack.push( x );

    XortElement retIP = m_RetStack.pop(); // restore IP
    if( !( retIP.bAccess & sys_Frame ) || retIP.bType != t_u4 ) return ERR_INTERNAL;
    m_dwIP = retIP._u4;

    return XORT_OK; 
}
int XRuntime::do_new( const InstructionData& primData )
{
    int iRet;
    //byte bCmdType  = primData.m_bTypeAddr & 0xF0;
    byte bAddr     = primData.m_bTypeAddr & 0x0F;
    dword dwObjectType = 0;

    switch( bAddr )
    {
    case 0:
        {
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            XortElement x = m_Stack.pop();
            if( x.bType != t_u4 ) return ERR_INVALID_TYPE;
            dwObjectType = x._u4;
            break;
        }
    case a_c:
        {
            if( primData.m_Value.bType != t_u4 ) return ERR_INVALID_PRIMCODE;
            dwObjectType = primData.m_Value._u4;
            break;
        }
    default: 
        return ERR_INVALID_PRIMCODE;
    }

    SymbolRef targetType = FindType( *m_pSymList, dwObjectType );
    if( targetType.isNULL() )
        return ERR_INVALID_TYPE;

    XortElement x;
    if( ( iRet = createXObject( targetType, NULL, &x._p ) ) != XORT_OK )
        return iRet;

    x.bType   = t_p;
    x.bAccess = ( targetType.m_dwFlags & f_const ) ? usr_VarR : usr_VarRW; // setup constant flag

    m_Stack.push( x );

    return iRet;
}
int XRuntime::do_get( const InstructionData& primData )
{
    int iRet;
    byte bCmdType  = primData.m_bTypeAddr & 0xF0;
    byte bAddr     = primData.m_bTypeAddr & 0x0F;

    switch( bAddr )
    {
    case 0: // ref, index -> value
        {
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            XortElement idx = m_Stack.pop();
            if( idx.bType != t_u2 ) return ERR_TYPES_MISMATCH;
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            XortElement refObj = m_Stack.pop();
            if( refObj.bType != t_p ) return ERR_TYPES_MISMATCH;
            XortElement val;
            if( ( iRet = refObj._p->Get( idx._u2, val ) ) == XORT_OK ) {
                if( !( val.bAccess & usr_VarR ) ) return ERR_INVALID_ACCESS;
                if( val.bType != bCmdType ) return ERR_TYPES_MISMATCH;
                m_Stack.push( val );
            }
            break;
        }
    case a_ti: // ... -> value
        {
            if( primData.m_Value.bType != t_u2 ) return ERR_INVALID_PRIMCODE;
            if( !m_Stack.canGet( m_dwStackBase ) ) return ERR_INVALID_STACK_IDX;
            XortElement& sysFr = m_Stack.get( m_dwStackBase );
            if( !( sysFr.bAccess & sys_Frame ) ) return ERR_INVALID_STACK_SYSFRAME;
            if( sysFr._ti == 0 ) return ERR_THIS_PTR_NULL;
            xobject *pObj = (xobject *)sysFr._ti;
            XortElement v;
            if( ( iRet = pObj->Get( primData.m_Value._u2, v ) ) == XORT_OK ) {
                if( v.bType != bCmdType ) return ERR_TYPES_MISMATCH;
                m_Stack.push( v );
            }
            break;
        }
    default: 
        return ERR_INVALID_PRIMCODE;
    }

    return iRet;
} 
int XRuntime::do_put( const InstructionData& primData )
{
    int iRet;
    byte bCmdType  = primData.m_bTypeAddr & 0xF0;
    byte bAddr     = primData.m_bTypeAddr & 0x0F;

    switch( bAddr )
    {
    case 0: // put.T    value, ref, index -> ...
        {
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            XortElement idx = m_Stack.pop();
            if( idx.bType != t_u2 ) return ERR_TYPES_MISMATCH;
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            XortElement refObj = m_Stack.pop();
            if( refObj.bType != t_p ) return ERR_TYPES_MISMATCH;
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            XortElement val = m_Stack.pop();
            if( !( val.bAccess & usr_VarR ) ) return ERR_INVALID_ACCESS;
            if( val.bType != bCmdType ) 
                return ERR_TYPES_MISMATCH;
            iRet = refObj._p->Put( idx._u2, val );
            break;
        }
    case a_ti: // put.ti.T  value -> ...
        {
            if( primData.m_Value.bType != t_u2 ) return ERR_INVALID_PRIMCODE;
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            XortElement v = m_Stack.pop();
            if( v.bAccess != usr_VarRW ) return ERR_INVALID_ACCESS;
            if( v.bType != bCmdType ) return ERR_TYPES_MISMATCH;
            if( !m_Stack.canGet( m_dwStackBase ) ) return ERR_INVALID_STACK_IDX;
            XortElement& sysFr = m_Stack.get( m_dwStackBase );
            if( !( sysFr.bAccess & sys_Frame ) ) return ERR_INVALID_STACK_SYSFRAME;
            if( sysFr._ti == 0 ) return ERR_THIS_PTR_NULL;
            xobject *pObj = (xobject *)sysFr._ti;
            iRet = pObj->Put( primData.m_Value._u2, v );
            break;
        }
    default: 
        return ERR_INVALID_PRIMCODE;
    }

    return iRet;
}
int XRuntime::do_invoke( const InstructionData& primData )
{
    int iRet;
    byte bCmdType  = primData.m_bTypeAddr & 0xF0;
    byte bAddr     = primData.m_bTypeAddr & 0x0F;
    dword dwProcIdx;
    xobject *pObj;

    switch( bAddr )
    {
    case 0: // invoke.T [arg1, arg2, ...argN,] ref, index -> (result)
        {
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            XortElement idx = m_Stack.pop();
            if( idx.bType != t_u2 ) return ERR_TYPES_MISMATCH;
            if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
            XortElement refObj = m_Stack.pop();
            if( refObj.bType != t_p ) return ERR_TYPES_MISMATCH;
            dwProcIdx = idx._u2;
            pObj = refObj._p; pObj->AddRef();
            break;
        }
    case a_ti: // invoke.ti.T   [arg1, arg2, ...argN] -> (result)
        {
            if( primData.m_Value.bType != t_u2 ) return ERR_INVALID_PRIMCODE;
            dwProcIdx = primData.m_Value._u2;
            if( !m_Stack.canGet( m_dwStackBase ) ) return ERR_INVALID_STACK_IDX;
            XortElement& sysFr = m_Stack.get( m_dwStackBase );
            if( !( sysFr.bAccess & sys_Frame ) ) return ERR_INVALID_STACK_SYSFRAME;
            if( sysFr._ti == 0 ) return ERR_THIS_PTR_NULL;
            pObj = (xobject *)sysFr._ti; pObj->AddRef();
            break;
        }
    default: 
        return ERR_INVALID_PRIMCODE;
    }

    symbolref pMethod = (symbolref)pObj->get_Method( dwProcIdx );
    if( !pMethod ) return ERR_INVALID_METHOD_INDEX;
    if( pMethod->m_dwType != bCmdType ) {
        if( pMethod->m_dwType < t_p && bCmdType == t_p )
            return ERR_TYPES_MISMATCH;
    }

    XortElement xSys; 
    xSys.bAccess = sys_Frame;
    
    if( pMethod->m_dwFlags & f_unspecnumargs ) { // apply the actual number of arguments for unspecified number of args
        if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
        XortElement argNo = m_Stack.pop();       // trick: we pop out the informational argument with the number of args
        if( argNo.bType != t_u1 ) return ERR_INVALID_TYPE;
        xSys.bType = argNo._u1;                  // and put the number of arguments into system frame
    } else {
        xSys.bType = pMethod->m_listMembers.size() - 1; // set number of arguments, skip localScope marker
    }

    xSys._ti = (dword)pObj;                // set this pointer
    xSys._asp = m_dwStackBase;             // save old stack base
    m_dwStackBase = m_Stack.push( xSys );  // create system frame
    
    xSys.bType = t_u4; xSys.bAccess = sys_Frame; xSys._u4 = m_dwIP;
    m_RetStack.push( xSys );               // save current IP
    iRet = pObj->Invoke( dwProcIdx, this );      // invoke object method
    pObj->Release();

    return iRet;
}
int XRuntime::do_gettype( const InstructionData& primData )
{
    if( ( primData.m_bTypeAddr & 0xF0 ) != t_p ) return ERR_INVALID_PRIMCODE;
    if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
    XortElement refObj = m_Stack.pop();
    if( refObj.bType != t_p ) return ERR_TYPES_MISMATCH;
    XortElement x; x.bType = t_u4; x.bAccess = usr_VarRW;
    x._u4 = refObj._p->GetType();
    m_Stack.push( x );
    return XORT_OK;
}
int XRuntime::do_enter( const InstructionData& primData )
{
    XortElement x;
    x.bType     = 0xFF;     // reserved
    x.bAccess   = sys_Scope;// marker
    x._ti       = 0;
    x._asp      = 0;        // install exception handler here!
    m_Stack.push( x );      // create system scope frame
    if( m_pDbgEvents ) m_pDbgEvents->onEnterFrame( this );
    return XORT_OK;
}
int XRuntime::do_leave( const InstructionData& primData )
{
    int bBrake = FALSE;
    if( m_pDbgEvents ) m_pDbgEvents->onLeaveFrame( this );
    do  // cleanup the stack till system scope frame
    {
        if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
        XortElement xClean = m_Stack.pop();
        if( xClean.bAccess & sys_Frame ) { // we never should reach to base procedure frame
            return ERR_INVALID_STACK;
        } else if( xClean.bAccess & sys_Scope ) {
            bBrake = TRUE;
        } 
        xClean.Clear();
    } while( !bBrake );
    return XORT_OK;
}  
int XRuntime::do_nop( const InstructionData& primData )
{ 
    return XORT_OK; // do nothing :)
}    
int XRuntime::do_dbgbreak( const InstructionData& primData )
{
    return XORT_OK;  // TODO: call debugger
}
int XRuntime::do_pack( const InstructionData& primData )
{
    byte bCmdType  = primData.m_bTypeAddr & 0xF0;
    byte bAddr     = primData.m_bTypeAddr & 0x0F;

    if( bCmdType != t_p ) return ERR_INVALID_TYPE;
    if( bAddr ) return ERR_INTERNAL; // should be 0

    if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
    XortElement xObj = m_Stack.pop();
    if( xObj.bAccess != usr_VarRW ) return ERR_INVALID_ACCESS;
    if( xObj.bType != bCmdType ) return ERR_TYPES_MISMATCH;

    xobject *pObj = (xobject *)xObj._p;
    if( !pObj ) return ERR_NULL_PTR;

    dword dwType = pObj->GetType();
    if( dwType <= t_p || dwType >= t_system ) return ERR_INVALID_TYPE;

    XObject *pByteArray = NULL;

    int iRet = pObj->Pack( (void**)&pByteArray );
    if( iRet != XORT_OK )
        return iRet;

    xObj.Clear();
    xObj.bAccess = usr_VarRW;
    xObj.bType = t_p;
    xObj.SetValue( pByteArray );
    m_Stack.push( xObj );

    return XORT_OK;
}
int XRuntime::do_upack( const InstructionData& primData )
{
    byte bCmdType  = primData.m_bTypeAddr & 0xF0;
    byte bAddr     = primData.m_bTypeAddr & 0x0F;

    if( bCmdType != t_p ) return ERR_INVALID_TYPE;
    if( bAddr ) return ERR_INTERNAL; // should be 0

    if( !m_Stack.canPop() ) return ERR_STACK_UNDERFLOW;
    XortElement& xObj = m_Stack.top();
    if( xObj.bAccess != usr_VarRW ) return ERR_INVALID_ACCESS;
    if( xObj.bType != bCmdType ) return ERR_TYPES_MISMATCH;

    xobject *pObj = (xobject *)xObj._p;
    if( !pObj ) return ERR_NULL_PTR;

    dword dwType = pObj->GetType();
    if( dwType <= t_p || dwType >= t_system ) return ERR_INVALID_TYPE;

    // Instruction is redundant. Do only basic checks here. The actual unpacking is done inside XNI object

    return XORT_OK;
}
int XRuntime::do_label( const InstructionData& primData )
{
    return ERR_INVALID_PRIMCODE; // should not happen
}  
//////////////////////////////////////////////////////////////////////////
// helper stuff
void XRuntime::DumpStack()
{
    dword dwCount = m_Stack.count();
    if( dwCount == 0 ) {
        DebugMessage( "STACK EMPTY" );
    } else {
        for( dword i = 0; i < dwCount; i++ )
        {
            const XortElement& x = m_Stack.get( i );
            DebugMessage( "%06d:    [ %02X | %02X | %08X %08X ]", i, x.bType, x.bAccess, x._ti, x._u4 );
        }
    }
}
//////////////////////////////////////////////////////////////////////////
// Objects factory.
int XRuntime::createXObject( SymbolRef objType, XortNativeInterface *pExternalObj, xobject **ppOut )
{
    xobjectref pObj = NULL;

    int iRet;

    if( objType.m_dwType == t_string )
    {
        pObj = new xstring();

    } else if( objType.m_dwType == t_xelement ) {

        pObj = new CXortElementImpl( this );

    } else if( objType.m_dwTemplateType == t_array ) {

        switch( objType.m_dwTemplSpecType )
        {
        case t_s1: pObj = new xarray_s1(); break;
        case t_u1: pObj = new xarray_u1(); break;
        case t_s2: pObj = new xarray_s2(); break;
        case t_u2: pObj = new xarray_u2(); break;
        case t_s4: pObj = new xarray_s4(); break;
        case t_u4: pObj = new xarray_u4(); break;
        case t_s8: pObj = new xarray_s8(); break;
        case t_u8: pObj = new xarray_u8(); break;
        case t_r4: pObj = new xarray_r4(); break;
        case t_r8: pObj = new xarray_r8(); break;
        case t_p : return ERR_INVALID_TYPE;
        default: // create object with custom type
            SymbolRef custObjType = FindType( *m_pSymList, objType.m_dwTemplSpecType );
            if( custObjType.isNULL() )
                return ERR_INVALID_TYPE;
            pObj = new xarray_xo();
            break; 
        }

    } else if( objType.m_dwTemplateType == t_list ) {

        switch( objType.m_dwTemplSpecType )
        {
        case t_s1: pObj = new xlist_s1();  break;
        case t_u1: pObj = new xlist_u1();  break;
        case t_s2: pObj = new xlist_s2();  break;
        case t_u2: pObj = new xlist_u2();  break;
        case t_s4: pObj = new xlist_s4();  break;
        case t_u4: pObj = new xlist_u4();  break;
        case t_s8: pObj = new xlist_s8();  break;
        case t_u8: pObj = new xlist_u8();  break;
        case t_r4: pObj = new xlist_r4();  break;
        case t_r8: pObj = new xlist_r8();  break;
        case t_p : return ERR_INVALID_TYPE;
        default: // create object with custom type
            SymbolRef custObjType = FindType( *m_pSymList, objType.m_dwTemplSpecType );
            if( custObjType.isNULL() )
                return ERR_INVALID_TYPE;
            pObj = new xlist_xo();
            break; 
        }

    } else if( objType.m_dwTemplateType == t_listiter ) { // this allows to create iterators outside of list... do we need this?

        switch( objType.m_dwTemplSpecType )
        {
        case t_s1: pObj = new CXListIteratorImpl<char,  xlist_s1>( t_s1 );  break;
        case t_u1: pObj = new CXListIteratorImpl<byte,  xlist_u1>( t_u1 );  break;
        case t_s2: pObj = new CXListIteratorImpl<short, xlist_s2>( t_s2 );  break;
        case t_u2: pObj = new CXListIteratorImpl<word,  xlist_u2>( t_u2 );  break;
        case t_s4: pObj = new CXListIteratorImpl<int,   xlist_s4>( t_s4 );  break;
        case t_u4: pObj = new CXListIteratorImpl<dword, xlist_u4>( t_u4 );  break;
        case t_s8: pObj = new CXListIteratorImpl<qlong, xlist_s8>( t_s8 );  break;
        case t_u8: pObj = new CXListIteratorImpl<qword, xlist_u8>( t_u8 );  break;
        case t_r4: pObj = new CXListIteratorImpl<float, xlist_r4>( t_r4 );  break;
        case t_r8: pObj = new CXListIteratorImpl<real,  xlist_r8>( t_r8 );  break;
        case t_p : return ERR_INVALID_TYPE;
        default: // create object with custom type
            SymbolRef custObjType = FindType( *m_pSymList, objType.m_dwTemplSpecType );
            if( custObjType.isNULL() )
                return ERR_INVALID_TYPE;
            pObj = new CXListIteratorImpl<xobjectref, xlist_xo>( t_p );
            break; 
        }
    } else { // custom object
        if( objType.m_dwFlags & f_import_obj ) {
            pObj = new XNIObject( this ); // create object from third-party dll
        } else {
            pObj = new XObject( this );   // create normal user object
        }
    }

    if( !pObj )
        return ERR_MEMORY_ALLOCATION;

    pObj->AddRef();
    pObj->SetType( objType.m_dwType );

    iRet = pObj->Init( &objType, pExternalObj );
    if( iRet == XORT_OK )
    {
        *ppOut = pObj;
    }
    else
    {
        pObj->Release();
        pObj = NULL;
    }

    return iRet;
}

symbolref XRuntime::get_FunctionByIndex( dword dwIdx )
{
    if( dwIdx >= m_Functions.count() )
        return NULL;

    symbolref pRet = m_Functions.get( dwIdx );
    return pRet;
}

XortElement* XRuntime::get_GlobalVariableByIndex( dword dwIdx )
{
    if( dwIdx >= m_Data.count() )
        return NULL;

    return (XortElement*)m_Data.ptr( dwIdx );
}

void XRuntime::DebugMessage( const char *lpszMsg, ... )
{
    char szBuf[1024];
    va_list argptr;
    va_start( argptr, lpszMsg );
    int iFmt = vsnprintf( szBuf, 1024, lpszMsg, argptr );
    va_end( argptr );
    szBuf[iFmt++] = '\r';
    szBuf[iFmt++] = '\n';
    szBuf[iFmt++] = 0;
    
    if( m_pDbgEvents )
        m_pDbgEvents->outputDebugMessage( szBuf );
#ifdef BUID_FOR_PC
    OutputDebugStringA( szBuf );
#endif
}
